package j.framework.log;

import j.util.SpringBeans;
import j.util.StringUtils;
import j.util.exception.ApplicationException;
import j.util.jdbc.JdbcUtils;
import j.util.pkgenerator.PG;
import org.apache.log4j.Category;
import org.apache.log4j.Priority;
import org.apache.log4j.jdbc.JDBCAppender;
import org.apache.log4j.spi.ErrorCode;
import org.apache.log4j.spi.LoggingEvent;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Iterator;

/**
 * User: jason
 * Date: 13-5-2 下午5:28
 */
public class CmsJDBCAppender extends JDBCAppender {
    private DataSource dataSource;
    private String driverClass = "com.mysql.jdbc.Driver";  //默认为mysql

    private void initDataSource(){
        DataSource ds = SpringBeans.getBean(DataSource.class);
        if(ds == null){
            throw new ApplicationException("初始化日志JDBCAppender时出错,没有找到数据源.");
        }
        dataSource = ds;
        Runtime.getRuntime().addShutdownHook(new Log4jHockThread());
    }

    private class Log4jHockThread extends Thread {
        @Override
        public void run() {
            System.out.println("log4jhock run ok.");
            CmsJDBCAppender.this.flushBuffer();
        }
    }
    @Override
    protected Connection getConnection() throws SQLException {
        //从数据库连接池中获取
        if(dataSource == null){
            synchronized (CmsJDBCAppender.class){
                if(null == dataSource){
                    initDataSource();
                }
            }
        }
        return dataSource.getConnection();
    }

    @Override
    protected void closeConnection(Connection con) {
        JdbcUtils.free(con, null);
    }

    @Override
    protected void execute(String sql) throws SQLException {
        //用jdbc方式向数据库中增加日志
        Connection conn = null;
        PreparedStatement pstmt = null;
        try{
            conn = this.getConnection();
            pstmt = conn.prepareStatement(sql);
            //设置主键参数
            pstmt.setString(1, PG.getNext("slg"));
            pstmt.executeUpdate();
        }catch(SQLException ignored){
            ignored.printStackTrace();
        }
        finally {
            JdbcUtils.free(conn, pstmt);
        }
    }

    @Override
    protected String getLogStatement(LoggingEvent event) {
        String fqnOfCategoryClass=event.fqnOfCategoryClass;
        Category logger= Category.getRoot();
        Priority level=event.level;
        String message=(String)event.getMessage();
        if(StringUtils.isNotEmpty(message) && message.length()>=200){
            //当消息体大于200时,则截取前200个字符
            message = message.substring(0,200);
        }
        Throwable throwable=null;
        RabbitLoggingEvent bEvent=new RabbitLoggingEvent(fqnOfCategoryClass,logger,level,message,throwable);
        return super.getLogStatement(bEvent);
    }

    @Override
    public void setDriver(String driverClass) {
        this.driverClass = driverClass;
    }

    @Override
    public void flushBuffer() {
        //Do the actual logging
        removes.ensureCapacity(buffer.size());
        for (Iterator i = buffer.iterator(); i.hasNext();) {
            try {
                LoggingEvent logEvent = (LoggingEvent)i.next();
                String sql = getLogStatement(logEvent);
                execute(sql);
                removes.add(logEvent);
            }
            catch (SQLException e) {
                errorHandler.error("Failed to excute sql", e,
                        ErrorCode.FLUSH_FAILURE);
            }
        }
        // remove from the buffer any events that were reported
        buffer.removeAll(removes);
        // clear the buffer of reported events
        removes.clear();
    }
}
